home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1996 March
/
EnigmA AMIGA RUN 05 (1996)(G.R. Edizioni)(IT)[!][issue 1996-03][Skylink CD IV].iso
/
earcd
/
unix
/
mesaamwn.lha
/
Mesa-Amiwin
/
demos
/
shadow.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-10-26
|
7KB
|
310 lines
/* shadow.c */
/*
* Use the stencil buffer to generate shadows. This demo inspired by
* an article in IRIS Universe Magazine, No. 18. This program is in
* the public domain.
*
* Brian Paul
*/
#include <math.h>
#include "gltk.h"
static GLfloat light_pos[4] = { 0.0, 10.0, 0.0, 1.0 };
static GLfloat view_rotx, view_roty;
static GLfloat ground_xrot, ground_yrot, ground_zrot;
static GLfloat ground_y;
/*
* These triangles cast the shadow.
*/
#define NUM_TRI 4
static GLfloat triangle[NUM_TRI][3][3] = {
0.5, 4.0, 0.5,
-0.5, 4.0, 0.5,
0.0, 4.0, 2.0,
0.5, 4.0, 0.5,
0.5, 4.0, -0.5,
2.0, 4.0, 0.0,
0.5, 4.0, -0.5,
-0.5, 4.0, -0.5,
0.0, 4.0, -2.0,
-0.5, 4.0, -0.5,
-0.5, 4.0, 0.5,
-2.0, 4.0, 0.0
};
static void init( void )
{
static GLfloat ambient[4] = {0.3, 0.3, 0.3, 1.0};
view_rotx = 50.0;
view_roty = 20.0;
ground_xrot = ground_yrot = ground_zrot = 0.0;
ground_y = 0.0;
glEnable( GL_DEPTH_TEST );
glDepthFunc( GL_LEQUAL );
glShadeModel( GL_FLAT );
glLightModelfv( GL_LIGHT_MODEL_AMBIENT, ambient );
glLightfv( GL_LIGHT0, GL_AMBIENT, ambient );
}
/*
* Draw the whole scene. For each frame we'll call this function twice.
* The first time with just ambient lighting, the second time with ambient
* and point source lighting.
*/
static void draw_scene( void )
{
static GLint ground = -1;
GLint i, j;
GLfloat x, y, z;
glPushMatrix();
glRotatef( ground_xrot, 1.0, 0.0, 0.0 );
glRotatef( ground_yrot, 0.0, 1.0, 0.0 );
glRotatef( ground_zrot, 0.0, 0.0, 1.0 );
glTranslatef( 0.0, ground_y, 0.0 );
if (ground==-1) {
/* make the ground checkerboard */
ground = glGenLists(1);
glNewList( ground, GL_COMPILE_AND_EXECUTE );
for (i=0;i<5;i++) {
for (j=0;j<5;j++) {
if ((i+j)%2) {
glColor3f( 0.0, 1.0, 0.0 );
}
else {
glColor3f( 0.0, 0.0, 1.0 );
}
glNormal3f( 0.0, 1.0, 0.0 );
x = i*2.0 - 5.0;
y = 0.0;
z = j*2.0 - 5.0;
glBegin( GL_POLYGON );
glVertex3f( x, y, z+2.0 );
glVertex3f( x+2.0, y, z+2.0 );
glVertex3f( x+2.0, y, z );
glVertex3f( x, y, z );
glEnd();
}
}
glEndList();
}
else {
/* draw ground checkerboard */
glCallList( ground );
}
glPopMatrix();
/* draw triangles */
glColor3f( 1.0, 0.0, 0.0 );
glNormal3f( 0.0, 1.0, 0.0 );
glBegin( GL_TRIANGLES );
for (i=0;i<NUM_TRI;i++) {
glVertex3fv( triangle[i][0] );
glVertex3fv( triangle[i][1] );
glVertex3fv( triangle[i][2] );
}
glEnd();
}
/*
* For each triangle in triangle list:
* For each edge of triangle:
* Construct a shadow volume boundary polygon by extending an edge away
* from the light source for an arbitrary distance.
* Draw the boundary polygon into the stencil planes, with invert
* stencil op, do depth test but don't update depth buffer.
* When finished, where stencil buffer = 1 we're in a shadow.
*/
static void draw_shadow_volumes( void )
{
GLint tri;
GLint i, j;
GLfloat v0[3], v1[3];
GLfloat p0[3], p1[3], p2[3], p3[3];
for (tri=0;tri<NUM_TRI;tri++) {
/* loop over triangle edges */
for (i=0;i<3;i++) {
j = (i+1) % 3;
/* v0 = vector from light to vertex i */
v0[0] = triangle[tri][i][0] - light_pos[0];
v0[1] = triangle[tri][i][1] - light_pos[1];
v0[2] = triangle[tri][i][2] - light_pos[2];
/* v1 = vector from light to vertex i+1 */
v1[0] = triangle[tri][j][0] - light_pos[0];
v1[1] = triangle[tri][j][1] - light_pos[1];
v1[2] = triangle[tri][j][2] - light_pos[2];
/* compute vertices of shadow volume boundary side */
p0[0] = triangle[tri][i][0];
p0[1] = triangle[tri][i][1];
p0[2] = triangle[tri][i][2];
p1[0] = triangle[tri][j][0];
p1[1] = triangle[tri][j][1];
p1[2] = triangle[tri][j][2];
p2[0] = p1[0] + v1[0] * 10.0;
p2[1] = p1[1] + v1[1] * 10.0;
p2[2] = p1[2] + v1[2] * 10.0;
p3[0] = p0[0] + v0[0] * 10.0;
p3[1] = p0[1] + v0[1] * 10.0;
p3[2] = p0[2] + v0[2] * 10.0;
/* draw the shadow volume boundary polygon */
glBegin( GL_POLYGON );
glVertex3fv( p0 );
glVertex3fv( p1 );
glVertex3fv( p2 );
glVertex3fv( p3 );
glEnd();
}
}
}
static void draw( void )
{
/* clear the buffers */
glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT
| GL_STENCIL_BUFFER_BIT );
/* transform by the view angle */
glPushMatrix();
glRotatef( view_rotx, 1.0, 0.0, 0.0 );
glRotatef( view_roty, 0.0, 0.0, 1.0 );
glLightfv( GL_LIGHT0, GL_POSITION, light_pos );
/* Draw scene with ambient lighting only */
glEnable( GL_LIGHTING );
glDisable( GL_LIGHT0 );
glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT );
glEnable( GL_COLOR_MATERIAL );
draw_scene();
/* Draw shadow volumes */
glDisable( GL_LIGHTING );
glStencilFunc( GL_ALWAYS, 0, 0xffffffff );
glStencilOp( GL_KEEP, GL_KEEP, GL_INVERT );
glEnable( GL_STENCIL_TEST );
glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
glDepthMask( GL_FALSE );
draw_shadow_volumes();
/* Draw scene with point sources where stencil==0 only */
glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
glDepthMask( GL_TRUE );
glEnable( GL_LIGHT0 );
glEnable( GL_LIGHTING );
glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
glEnable( GL_COLOR_MATERIAL );
glStencilFunc( GL_EQUAL, 0, 0xffffffff ); /* draw where stencil==0 */
glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
draw_scene();
/* all done */
glDisable( GL_STENCIL_TEST );
glDisable( GL_LIGHT0 );
glPopMatrix();
glFlush();
tkSwapBuffers();
}
/* spin and xlate the ground */
static void idle( void )
{
ground_yrot -= 2.0;
ground_xrot = sin(ground_yrot*0.1) * 10.0;
ground_zrot = cos(ground_yrot*0.1) * 10.0;
ground_y = sin( ground_yrot*0.15) * 2.0;
}
/* change view angle, exit upon ESC */
static GLenum key(int k, GLenum mask)
{
switch (k) {
case TK_UP:
view_rotx += 5.0;
return GL_TRUE;
case TK_DOWN:
view_rotx -= 5.0;
return GL_TRUE;
case TK_LEFT:
view_roty += 5.0;
return GL_TRUE;
case TK_RIGHT:
view_roty -= 5.0;
return GL_TRUE;
case TK_ESCAPE:
tkQuit();
}
return GL_FALSE;
}
/* new window size or exposure */
static void reshape( int width, int height )
{
glViewport(0, 0, (GLint)width, (GLint)height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 50.0 );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef( 0.0, 0.0, -35.0 );
}
main()
{
tkInitPosition(0, 0, 300, 300);
tkInitDisplayMode( TK_RGB | TK_DEPTH | TK_DOUBLE | TK_STENCIL | TK_DIRECT );
if (tkInitWindow("Stencil Shadow") == GL_FALSE) {
tkQuit();
}
init();
tkExposeFunc( reshape );
tkReshapeFunc( reshape );
tkKeyDownFunc( key );
tkIdleFunc( idle );
tkDisplayFunc( draw );
tkExec();
}